package com.xuanyue.db.xuan.core.orm;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.xuanyue.db.xuan.core.table.expr.ExprValue;
import com.xuanyue.db.xuan.core.table.expr.ExprValueType;
/**
 * 对象转ExprValue
 * 规则： 对象属性和map的key忽略大小写
 * @author 解观海
 * @email guanhaixie@sina.cn
 * @date 2021年1月19日
 *
 */
public class OrmUtils {
	
	@SuppressWarnings("unchecked")
	private static ExprValue field2ExprValue(Field f,Object tar) throws IllegalArgumentException, IllegalAccessException{
		ExprValue ev = new ExprValue();
		Class<?> type = f.getType();
		if(int.class==type||Integer.class==type) {
			ev.setType(ExprValueType.INT);
			ev.setValue(tar);
		}else if(boolean.class==type||Boolean.class==type) {
			ev.setType(ExprValueType.BOOLEAN);
			ev.setValue(tar);
		}else if(float.class==type||Float.class==type) {
			ev.setType(ExprValueType.FLOAT);
			ev.setValue(tar);
		}else if(long.class==type||Long.class==type) {
			ev.setType(ExprValueType.LONG);
			ev.setValue(tar);
		}else if(Date.class==type) {
			ev.setType(ExprValueType.DATE);
			ev.setValue(tar);
		}else if(Map.class==type) {
			Map<String,Object> x = (Map<String,Object>)tar;
			Map<String,ExprValue> v = new HashMap<>();
			for(Entry<String,Object> en:x.entrySet()) {
				v.put(en.getKey().toLowerCase(), obj2ExprValue(en.getValue())    );
			}
			ev.setType(ExprValueType.MAP);
			ev.setValue(v);
		}else if(List.class==type){
			List<Object> x = (List<Object>)tar;
			List<ExprValue> v = new ArrayList<>();
			for(Object o:x) {
				v.add( obj2ExprValue(o) );
			}
			ev.setType(ExprValueType.ARRAY);
			ev.setValue(v);
		}else {
			Field[] fs = type.getDeclaredFields();
			for(Field subf:fs) {
				subf.setAccessible(true);
			}
			Map<String,ExprValue> v = new HashMap<String,ExprValue>();
			for(Field subf:fs) {
				if(Modifier.isStatic( subf.getModifiers() )) {
					continue;
				}
				v.put(subf.getName().toLowerCase(), field2ExprValue(subf, subf.get(tar))   );
			}
			ev.setType(ExprValueType.MAP  );
			ev.setValue(v);
		}
		return ev;
	}
	/**
	 * java bean 转 ExprValue
	 * @param obj
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @author 解观海
	 * @date 2021年1月20日
	 */
	@SuppressWarnings("unchecked")
	public static ExprValue obj2ExprValue(Object obj) throws IllegalArgumentException, IllegalAccessException{
		Class<?> type = obj.getClass();
		ExprValue ev = new ExprValue();
		if(List.class.isInstance(obj)) {
			List<Object> x = (List<Object>)obj;
			List<ExprValue> v = new ArrayList<>();
			for(Object o:x) {
				v.add(obj2ExprValue(o) );
			}
			ev.setType(ExprValueType.ARRAY  );
			ev.setValue(v);
		}else if(Map.class.isInstance(obj)) {
			Map<String,Object> x = (Map<String,Object>)obj;
			Map<String,ExprValue> v = new HashMap<String,ExprValue>();
			for(String key:x.keySet()) {
				v.put(key.toLowerCase(),obj2ExprValue( x.get(key) ) );
			}
			ev.setType(ExprValueType.MAP  );
			ev.setValue(v);
		}else if(int.class==type||Integer.class==type) {
			ev.setType(ExprValueType.INT);
			ev.setValue(obj);
		}else if(boolean.class==type||Boolean.class==type) {
			ev.setType(ExprValueType.BOOLEAN);
			ev.setValue(obj);
		}else if(float.class==type||Float.class==type) {
			ev.setType(ExprValueType.FLOAT);
			ev.setValue(obj);
		}else if(long.class==type||Long.class==type) {
			ev.setType(ExprValueType.LONG);
			ev.setValue(obj);
		}else if(Date.class==type) {
			ev.setType(ExprValueType.DATE);
			ev.setValue(obj);
		}else {
			Field[] fs = obj.getClass().getDeclaredFields();
			for(Field f:fs) {
				f.setAccessible(true);
			}
			Map<String,ExprValue> v = new HashMap<String,ExprValue>();
			for(Field f:fs) {
				if(Modifier.isStatic( f.getModifiers() )) {
					continue;
				}
				v.put(f.getName().toLowerCase(), field2ExprValue(f, f.get(obj)));
			}
			ev.setType(ExprValueType.MAP  );
			ev.setValue(v);
		}
		
		return ev;
	}

	private static Object evToObj(ExprValue ev) throws Exception{
		return evToObj(ev,null);
	}
	private static Object evToObj(ExprValue ev,Class<?> cla) throws Exception{
		if(ExprValueType.ARRAY.is(ev.getType())) {
			List<Object> v = new ArrayList<>();
			List<ExprValue> x = ev.getValue();
			for(ExprValue e:x) {
				v.add( evToObj(e) );
			}
			return v;
		}else if(ExprValueType.MAP.is(ev.getType())) {
			Map<String,ExprValue> x = ev.getValue();
			if(cla==null||Map.class.isAssignableFrom(cla)) {
				Map<String,Object> v = new HashMap<>();
				for(Entry<String,ExprValue> en:x.entrySet()) {
					v.put(en.getKey().toLowerCase(), evToObj(en.getValue()));
				}
				return v;
			}else {
				Field[] fs = cla.getDeclaredFields();
				for(Field f:fs) {
					f.setAccessible(true);
				}
				Object v = cla.newInstance();
				for(Field f:fs) {
					if(Modifier.isStatic( f.getModifiers() )) {
						continue;
					}
					if(x.get(f.getName().toLowerCase())!=null) {
						f.set(v, evToObj(x.get(f.getName().toLowerCase()), f.getType() ));
					}
				}
				return v;
			}
		}else {
			return ev.getValue();
		}
	}
	
	/**
	 * ExprValue 转  java bean
	 * @param <T>
	 * @param ev
	 * @param cla
	 * @return
	 * @throws Exception
	 * @author 解观海
	 * @date 2021年1月20日
	 */
	@SuppressWarnings("unchecked")
	public static <T>T exprValue2Obj(ExprValue ev,Class<T> cla) throws Exception{
		return (T)evToObj(ev, cla);
	}
	
	
}
